/**
 * @file debug_cli.cpp
 * @brief VimL虚拟机调试命令行界面实现
 * @author VimLVM Team
 * @date 2025
 */

#include "viml/debug_cli.h"
#include "viml/debugger.h"
#include <iostream>
#include <sstream>
#include <algorithm>

namespace viml {

class DebugCLIImpl : public DebugEventHandler {
public:
    DebugCLIImpl(Debugger& debugger, std::istream& in, std::ostream& out)
        : debugger_(debugger), in_(in), out_(out), running_(true) {}

    void on_event(DebugEvent event, size_t line, const std::string& message) override {
        switch (event) {
            case DebugEvent::BREAKPOINT_HIT:
                out_ << "Breakpoint hit at line " << line << std::endl;
                break;
            case DebugEvent::STEP_COMPLETE:
                out_ << "Step complete at line " << line << std::endl;
                break;
            case DebugEvent::EXCEPTION:
                out_ << "Exception: " << message << " at line " << line << std::endl;
                break;
            case DebugEvent::PROGRAM_EXIT:
                out_ << "Program exited" << std::endl;
                running_ = false;
                break;
        }
        print_location();
    }

    void run() {
        debugger_.set_event_handler(std::make_unique<DebugCLIImpl>(*this));
        debugger_.start_debugging();
        
        print_help();
        
        std::string line;
        while (running_ && std::getline(in_, line)) {
            handle_command(line);
            if (debugger_.vm().state() == VMState::HALTED) {
                running_ = false;
            }
        }
    }

private:
    void print_help() {
        out_ << "\nVimL调试器命令:\n"
             << "  h, help      - 显示帮助\n"
             << "  b <line>     - 在指定行设置断点\n"
             << "  d <line>     - 删除指定行的断点\n"
             << "  lb           - 列出所有断点\n"
             << "  s            - 单步进入\n"
             << "  n            - 单步跳过\n"
             << "  c            - 继续执行\n"
             << "  p <var>      - 打印变量值\n"
             << "  l            - 列出局部变量\n"
             << "  g            - 列出全局变量\n"
             << "  bt           - 显示调用栈\n"
             << "  q            - 退出调试器\n\n";
    }

    void print_location() {
        if (debugger_.vm().call_stack().empty()) {
            out_ << "(no location)" << std::endl;
            return;
        }

        auto line = debugger_.get_current_line();
        auto func = debugger_.get_current_function();
        out_ << "=> " << func << ":" << line << std::endl;
    }

    void print_variables() {
        out_ << "\n局部变量:\n";
        auto locals = debugger_.get_local_variables();
        for (const auto& [name, value] : locals) {
            out_ << "  " << name << " = " << value.to_string() << std::endl;
        }

        out_ << "\n全局变量:\n";
        auto globals = debugger_.get_global_variables();
        for (const auto& [name, value] : globals) {
            out_ << "  " << name << " = " << value.to_string() << std::endl;
        }
    }

    void print_call_stack() {
        out_ << "\n调用栈:\n";
        auto stack = debugger_.get_call_stack();
        for (size_t i = 0; i < stack.size(); ++i) {
            const auto& frame = stack[i];
            out_ << "  [#" << i << "] " << frame.function_name 
                 << " at line " << frame.line << std::endl;
        }
    }

    void handle_command(const std::string& command) {
        std::istringstream iss(command);
        std::string cmd;
        iss >> cmd;

        if (cmd.empty()) return;

        if (cmd == "h" || cmd == "help") {
            print_help();
        } else if (cmd == "b") {
            size_t line;
            if (iss >> line) {
                debugger_.add_breakpoint("main", line);
                out_ << "Breakpoint set at line " << line << std::endl;
            } else {
                out_ << "Usage: b <line>" << std::endl;
            }
        } else if (cmd == "d") {
            size_t line;
            if (iss >> line) {
                debugger_.remove_breakpoint("main", line);
                out_ << "Breakpoint removed from line " << line << std::endl;
            } else {
                out_ << "Usage: d <line>" << std::endl;
            }
        } else if (cmd == "lb") {
            auto breakpoints = debugger_.list_breakpoints();
            out_ << "Breakpoints:" << std::endl;
            for (const auto& [file, line] : breakpoints) {
                out_ << "  " << file << ":" << line << std::endl;
            }
        } else if (cmd == "s") {
            debugger_.step_into();
        } else if (cmd == "n") {
            debugger_.step_over();
        } else if (cmd == "c") {
            debugger_.continue_execution();
        } else if (cmd == "p") {
            std::string var_name;
            if (iss >> var_name) {
                Value value = debugger_.get_variable(var_name);
                out_ << var_name << " = " << value.to_string() << std::endl;
            } else {
                out_ << "Usage: p <variable>" << std::endl;
            }
        } else if (cmd == "l") {
            auto locals = debugger_.get_local_variables();
            out_ << "Local variables:" << std::endl;
            for (const auto& [name, value] : locals) {
                out_ << "  " << name << " = " << value.to_string() << std::endl;
            }
        } else if (cmd == "g") {
            auto globals = debugger_.get_global_variables();
            out_ << "Global variables:" << std::endl;
            for (const auto& [name, value] : globals) {
                out_ << "  " << name << " = " << value.to_string() << std::endl;
            }
        } else if (cmd == "bt") {
            print_call_stack();
        } else if (cmd == "q") {
            running_ = false;
        } else {
            out_ << "Unknown command: " << cmd << std::endl;
            out_ << "Type 'help' for available commands." << std::endl;
        }
    }

    Debugger& debugger_;
    std::istream& in_;
    std::ostream& out_;
    bool running_;
};

DebugCLI::DebugCLI() : vm_(std::make_unique<VM>()), compiler_(std::make_unique<Compiler>()), running_(false) {}

bool DebugCLI::load_file(const std::string& filename) {
    try {
        compiler_->load_file(filename);
        current_file_ = filename;
        return true;
    } catch (const std::exception& e) {
        std::cerr << "Error loading file: " << e.what() << std::endl;
        return false;
    }
}

void DebugCLI::run() {
    if (current_file_.empty()) {
        std::cerr << "No file loaded. Use load_file() first." << std::endl;
        return;
    }

    try {
        auto function = compiler_->compile();
        if (!function) {
            std::cerr << "Compilation failed" << std::endl;
            return;
        }

        Debugger debugger(*vm_);
        DebugCLIImpl cli(debugger, std::cin, std::cout);
        cli.run();

    } catch (const std::exception& e) {
        std::cerr << "Runtime error: " << e.what() << std::endl;
    }
}

} // namespace viml